# coding=utf-8

"""
@Author: LiangChao
@Email: kevinleong1011@hotmail.com

@Desc: 
"""


def compare(actual, expected, path=None):
    differences = []
    path = path or []
    if isinstance(actual, list) and isinstance(expected, list):
        i = 0
        for item in actual:
            path.append(f'[{i}]')
            expect_value = expected[i]
            _differences = compare(item, expect_value, path)
            i += 1
            differences.extend(_differences)
            path.pop()
    elif isinstance(actual, dict) and isinstance(expected, dict):
        for k, v in actual.items():
            path.append(f'/{k}')
            expect_value = expected.get(k)
            _differences = compare(v, expect_value, path)
            differences.extend(_differences)
            path.pop()
    elif hasattr(actual, 'compare'):
        different = actual.compare(expected, path)
        if different:
            differences.append((''.join(path), actual, expected))
    else:
        if actual != expected:
            differences.append((''.join(path), actual, expected))
    return differences


if __name__ == '__main__':
    actual = {
        'name': 'Mary',
        'books': [
            {
                'name': 'Python'
            }, {
                'name': 'Java'
            }
        ]
    }
    expected = {
        'name': 'Mike',
        'books': [
            {
                'name': 'Java'
            }, {
                'name': 'Python'
            }
        ]
    }
    print(compare(actual, expected))
